/**
 *
 */
package junior.util.io;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**拦截输出流的close和flush方法，<b>非单例模式</b>
 * 应用场景：当我们把流交给下一个节点去，我们不能确定下一个节点会不会关掉流，
 * 而我们又想在下个节点调用完后继续使用流，这时我们需要对close或flush方法进行拦截
 * @author WuBo
 * @CreateDate 2010-9-29
 * @version 1.0.01
 */
public class ProxyOutputStream extends OutputStream {
    private OutputStream os;
    
    private ProxyOutputStream(OutputStream os) {
        this.os = os;
    }
    
    public static ProxyOutputStream getInstance(OutputStream os, boolean allowClose, boolean allowFlush) {
        return (ProxyOutputStream) Proxy.newProxyInstance(
                ProxyOutputStream.class.getClassLoader(),
                new Class[]{ProxyOutputStream.class},
                new DefaultInvocationHandler(
                        new ProxyOutputStream(os),
                        allowClose,
                        allowFlush)
        );
    }
    
    
    protected static class DefaultInvocationHandler implements InvocationHandler {
        private OutputStream target;
        private boolean allowClose;
        private boolean allowFlush;
        
        public DefaultInvocationHandler(OutputStream os, boolean allowClose, boolean allowFlush) {
            target = os;
            this.allowClose = allowClose;
            this.allowFlush = allowFlush;
        }
        
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            if (!allowClose && "close".equals(method.getName())) {
                return null;
            }
            if (!allowFlush && "flush".equals(method.getName())) {
                return null;
            }
            return method.invoke(target, args);
        }
    }
    
    /**
     * 实际close方法调用
     * @throws IOException
     */
    public void realClose() throws IOException {
        os.close();
    }
    
    /**
     * 实际flush方法调用
     */
    public void realFlush() throws IOException {
        os.flush();
    }
    
    @Override
    public void write(int b) throws IOException {
        os.write(b);
    }
    
}
